<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="referrer" content="no-referrer" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>3D轮播图</title>
    <style>
      /* 基本样式 */
      :root {
        --max-width: 180px;
        --perspective: 1200px;
        --radius: 450px;
      }

      body {
        margin: 0;
        padding: 0;
        display: flex;
        justify-content: center;
        align-items: center;
        min-height: 100vh;
        background-color: #f0f0f0;
        font-family: Arial, sans-serif;
      }

      #swipe3D {
        perspective: var(--perspective);
        width: 100%;
        max-width: 1200px;
        overflow: hidden;
        margin: 0 auto;
        padding: 50px 0;
        position: relative;
      }

      .spinner {
        transform-style: preserve-3d;
        transform-origin: 50% 50% calc(-1 * var(--radius));
        height: 300px;
        transition: transform 0.8s cubic-bezier(0.23, 1, 0.32, 1);
        position: relative;
      }

      .spinner img {
        position: absolute;
        left: 50%;
        top: 50%;
        width: var(--max-width);
        height: 200px;
        object-fit: cover;
        transform-origin: 50% 50% calc(-1 * var(--radius));
        transform-style: preserve-3d;
        transition: all 0.3s ease-out;
        margin-left: calc(-1 * var(--max-width) / 2);
        margin-top: -100px;
        border-radius: 8px;
        box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15);
        z-index: 99999;
        cursor: pointer;
      }

      /* 控制轮播图的指示器 */
      .indicators {
        display: flex;
        justify-content: center;
        margin-top: 30px;
      }

      .indicator {
        width: 10px;
        height: 10px;
        border-radius: 50%;
        background-color: rgba(0, 0, 0, 0.2);
        margin: 0 5px;
        cursor: pointer;
        transition: background-color 0.3s;
      }

      .indicator.active {
        background-color: rgba(0, 0, 0, 0.6);
      }

      /* 导航按钮 */
      .nav-btn {
        position: absolute;
        top: 50%;
        transform: translateY(-50%);
        width: 40px;
        height: 40px;
        background-color: rgba(255, 255, 255, 0.8);
        border-radius: 50%;
        display: flex;
        align-items: center;
        justify-content: center;
        cursor: pointer;
        box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
        transition: all 0.3s;
        z-index: 10;
      }

      .nav-btn:hover {
        background-color: white;
        box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
      }

      .nav-btn.prev {
        left: 20px;
      }

      .nav-btn.next {
        right: 20px;
      }
    </style>
  </head>
  <body>
    <div id="swipe3D">
      <div class="nav-btn prev" onclick="rotate(-1,true)">&#10094;</div>
      <div class="nav-btn next" onclick="rotate(1,true)">&#10095;</div>
      <div class="spinner" style="transform: rotateY(0deg)"></div>
      <div class="indicators"></div>
    </div>

    <script>
      // 配置参数
      const config = {
        maxWidth: "180px",
        speed: 1500, // 轮播速度
        multiple: 1.2, // 鼠标悬停放大倍速
        autoPlay: true, // 是否自动轮播
        imgList: [
          "https://img0.baidu.com/it/u=1446729335,4267600834&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500",
          "https://img2.baidu.com/it/u=2922694860,2270800253&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500",
          "https://img0.baidu.com/it/u=595403291,2269048245&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500",
          "https://img0.baidu.com/it/u=1164365158,2722332607&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500",
          "https://img2.baidu.com/it/u=9876582,1040648435&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500",
          "https://img1.baidu.com/it/u=2172054385,2684839842&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500",
          "https://img1.baidu.com/it/u=1879107733,3573789717&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500",
          "https://img2.baidu.com/it/u=1720323410,218932174&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500",
          "https://img1.baidu.com/it/u=2479779032,1379361694&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500",
          "https://img1.baidu.com/it/u=537208727,895387248&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500",
          "https://img1.baidu.com/it/u=3310720258,943543712&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500",
          "https://img2.baidu.com/it/u=2165957654,3023194084&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500",
          "https://img0.baidu.com/it/u=1280320387,1585665801&fm=253&fmt=auto&app=138&f=JPEG?w=368&h=368",
          "https://img0.baidu.com/it/u=1403512971,1919400898&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500",
          "https://img0.baidu.com/it/u=707869343,3146161581&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500",
        ],
      };

      // 初始化状态
      let angle = 0;
      let currentIndex = 0;
      let mouseHover = false;
      let autoPlayInterval;
      const spinner = document.querySelector(".spinner");
      const indicators = document.querySelector(".indicators");
      const rotationDuration = 800; // 与CSS中transition时间匹配
      const totalImages = config.imgList.length;
      const degreesPerImage = 360 / totalImages;
      let lastEnterImg = null;

      const swipe3D = document.getElementById("swipe3D");
      //获取当前展示的图片
      swipe3D.addEventListener("click", (e) => {
        const index = judgeImg(e);
        if (index == -1) return;
        handleImageClick((totalImages - index) % totalImages);
      });
      swipe3D.addEventListener("mousemove", (e) => {
        const index = judgeImg(e);
        if (index == -1) {
          if (!lastEnterImg) return;
          handleMouseLeave({ target: lastEnterImg });
          lastEnterImg = null;
          swipe3D.style.cursor = "auto";
          return;
        }
        const img = document.querySelector(
          `.spinner img[data-index="${index}"]`
        );
        swipe3D.style.cursor = "pointer";
        if (lastEnterImg == img) return;
        handleMouseEnter({ target: img });
        lastEnterImg = img;
      });

      function judgeImg(e) {
        const target = e.target;
        if (target.tagName === "IMG") {
          return -1;
        }
        if (target.classList.contains("nav-btn")) {
          return -1;
        }
        const imgs = document.querySelectorAll(".spinner img");
        const spinner = document.querySelector(".spinner");
        const spinnerRect = spinner.getBoundingClientRect();
        const spinnerRotateY = spinner.style.transform.match(
          /rotateY\((-?\d+)deg\)/
        )[1];
        const rect = swipe3D.getBoundingClientRect();

        const x = e.pageX;
        const y = e.pageY;
        for (let img of imgs) {
          const index = img.dataset.index;
          const rotateY = img.style.transform.match(/rotateY\((-?\d+)deg\)/)[1];
          const angle = Math.abs(
            (Number(spinnerRotateY) + Number(rotateY)) % 360
          );
          if (
            degreesPerImage >= angle ||
            360 - degreesPerImage <= angle ||
            angle == degreesPerImage * 9
          ) {
            const imgRect = img.getBoundingClientRect();
            const imgX = imgRect.x;
            const imgY = imgRect.y;
            const imgWidth = imgRect.width;
            const imgHeight = imgRect.height;
            if (
              x > imgX &&
              x < imgX + imgWidth &&
              y > imgY &&
              y < imgY + imgHeight
            ) {
              return index;
            }
          }
        }
        return -1;
      }

      // 动态创建图片元素
      config.imgList.forEach((src, index) => {
        const img = document.createElement("img");
        img.src = src;
        img.dataset.index = index;

        // 计算每个图片的旋转角度
        const rotateAngle = -degreesPerImage * index;
        img.style.transform = `rotateY(${rotateAngle}deg) translateZ(450px)`;

        img.addEventListener("mouseenter", handleMouseEnter);
        img.addEventListener("mouseleave", handleMouseLeave);
        img.addEventListener("click", () =>
          handleImageClick((totalImages - index) % totalImages)
        );
        spinner.appendChild(img);

        // 创建指示器
        const indicator = document.createElement("div");
        indicator.className = "indicator" + (index === 0 ? " active" : "");
        indicator.dataset.index = index;
        indicator.addEventListener("click", () => goToSlide(index));
        indicators.appendChild(indicator);
      });

      function startAutoPlay() {
        // 自动轮播
        if (mouseHover || !config.autoPlay) return;
        if (autoPlayInterval) clearInterval(autoPlayInterval);
        autoPlayInterval = setInterval(() => {
          if (!mouseHover) {
            rotate(1);
          }
        }, config.speed);
      }

      // 启动自动轮播
      startAutoPlay();

      function handleMouseEnter(e) {
        // 鼠标移入事件
        const img = e.target;
        img.style.transform = `${img.style.transform} scale(${config.multiple})`;
        img.style.boxShadow = "0 15px 30px rgba(0, 0, 0, 0.25)";
        img.style.zIndex = "10";
        mouseHover = true;
        stopAutoPlay();
      }

      function handleMouseLeave(e) {
        // 鼠标离开事件
        const img = e.target;
        const rotateAngle = -degreesPerImage * img.dataset.index;
        img.style.transform = `rotateY(${rotateAngle}deg) translateZ(450px)`;
        img.style.boxShadow = "0 10px 25px rgba(0, 0, 0, 0.15)";
        img.style.zIndex = "1";
        mouseHover = false;
        startAutoPlay();
      }

      function handleImageClick(index) {
        // 图片点击事件
        stopAutoPlay();
        goToSlide(index);
      }

      function rotate(direction, flag = false) {
        // 控制轮播
        if (flag) {
          stopAutoPlay();
        }
        // 计算目标索引
        const newIndex = (currentIndex + direction + totalImages) % totalImages;

        // 计算最短旋转路径
        let angleDiff = newIndex - currentIndex;

        // 确保旋转方向是最短路径
        if (angleDiff > totalImages / 2) {
          angleDiff -= totalImages;
        } else if (angleDiff < -totalImages / 2) {
          angleDiff += totalImages;
        }

        // 更新当前索引和角度
        currentIndex = newIndex;
        angle += angleDiff * degreesPerImage;

        updateSlide(flag);
      }

      function goToSlide(index) {
        //角度计算
        stopAutoPlay();

        // 计算最短旋转路径
        let angleDiff = index - currentIndex;

        // 确保旋转方向是最短路径
        if (angleDiff > totalImages / 2) {
          angleDiff -= totalImages;
        } else if (angleDiff < -totalImages / 2) {
          angleDiff += totalImages;
        }

        // 更新当前索引和角度
        currentIndex = index;
        angle += angleDiff * degreesPerImage;

        updateSlide(true);
      }

      function updateSlide(flag = false) {
        // 切换幻灯片
        // 使用负角度进行旋转，确保顺时针旋转
        spinner.style.transform = `rotateY(${-angle}deg)`;

        // 更新指示器状态
        document.querySelectorAll(".indicator").forEach((indicator, i) => {
          if (i === currentIndex) {
            indicator.classList.add("active");
          } else {
            indicator.classList.remove("active");
          }
        });
        if (flag) {
          startAutoPlay();
        }
      }

      function stopAutoPlay() {
        // 停止自动轮播
        clearInterval(autoPlayInterval);
        autoPlayInterval = null;
      }

      // 响应窗口大小变化
      window.addEventListener("resize", updateSlide);

      // 键盘控制
      window.addEventListener("keydown", (e) => {
        if (e.key === "ArrowLeft") rotate(-1, true);
        if (e.key === "ArrowRight") rotate(1, true);
      });
    </script>
  </body>
</html>
